package jwt

import (
	"github.com/dgrijalva/jwt-go"
	"github.com/gogf/gf/crypto/gmd5"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/util/gconv"
	"time"
)

func GenerateLoginToken(memberId uint, realname string) (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"member_id":       memberId,
		"member_realname": realname,
		"jwt_version":     g.Cfg().GetString("jwt.version", "1.0"),
		"exp":             time.Now().Add(g.Cfg().GetDuration("jwt.expires", 1) * time.Minute).Unix(),
	})
	tokenString, err := token.SignedString([]byte(g.Cfg().GetString("jwt.sign", "gdshop")))
	if err == nil {
		tokenStringMd5 := gmd5.MustEncryptString(tokenString)
		g.Redis().Do("HSET", "VerifyLoginToken",
			tokenStringMd5, memberId)

		if g.Cfg().GetBool("site.OnlyOneLogin", false) {
			// 只允许在一个地点登录
			g.Redis().Do("HSET", "VerifyLoginTokenMemberId",
				memberId, tokenStringMd5)
			// 删除 VerifyLoginToken 里面多余的 数据
			verifyLoginTokens, _ := g.Redis().DoVar("HGETALL", "VerifyLoginToken")
			// 使用批量操作
			conn := g.Redis().Conn()
			defer conn.Close()
			for key, value := range verifyLoginTokens.Map() {
				if gconv.String(value) == gconv.String(memberId) && tokenStringMd5 != key {
					// 使用批量操作
					conn.Send("HDEL", "VerifyLoginToken", key)
				}
			}
			conn.Flush()
		}
	}
	return tokenString, err
}

func VerifyLoginToken(tokenString string) uint {
	if tokenString == "" {
		return 0
	}
	// 不为空，查缓存
	v, _ := g.Redis().DoVar("HGET",
		"VerifyLoginToken",
		gmd5.MustEncryptString(tokenString))
	if v != nil && v.String() != "" {
		// 是否只允许一个用户登录
		if g.Cfg().GetBool("site.OnlyOneLogin", false) {
			// 只允许在一个地点登录
			// 反查当前用户ID是否等于token
			memberToken, _ := g.Redis().DoVar("HGET", "VerifyLoginTokenMemberId",
				v.Uint())
			if memberToken.IsNil() || memberToken.IsEmpty() {
				return 0
			}

			// 对比
			if memberToken.String() != gmd5.MustEncryptString(tokenString) {
				// 不相等，返回失败
				return 0
			} else {
				return v.Uint()
			}
		}
		return v.Uint()
	} else {
		return 0
	}
	/*
		hmacSampleSecret := []byte(g.Cfg().GetString("jwt.sign", "gdshop"))
		token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
			// Don't forget to validate the alg is what you expect:
			if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
			}

			// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
			return hmacSampleSecret, nil
		})
		if err != nil {
			// 解析失败
			return 0
		}
		claims, ok := token.Claims.(jwt.MapClaims)
		if ok && token.Valid {
			// 验证通过
			g.Redis().Do("HSET", "VerifyLoginToken", gmd5.MustEncryptString(tokenString), claims["member_id"])

			return gconv.Uint(claims["member_id"])
		} else {
			// 验证不通过
			return 0
		}
	*/
}

func Layout(memberId int, tokenString string) {
	if tokenString == "" {
		return
	}
	g.Redis().Do("HDEL", "VerifyLoginToken", gmd5.MustEncryptString(tokenString))
	// 删除
	g.Redis().Do("HDEL", "VerifyLoginTokenMemberId", memberId)
}
